<?php

namespace app\admin\controller\auth;
use app\admin\command\Api\library\Extractor;
use app\admin\model\AuthGroup;
use app\common\controller\Backend;
use fast\Tree;
use think\Cache;
use fast\Random;
use fast\Cols;
use fast\Date;

/**
 * 角色组
 *
 * @icon fa fa-group
 * @remark 角色组可以有多个,角色有上下级层级关系,如果子角色有角色组和管理员的权限则可以派生属于自己组别下级的角色组或管理员
 */
class Group extends Backend
{

    protected $model = null;
    //当前登录管理员所有子组别
    protected $childrenGroupIds = [];
    //当前组别列表数据
    protected $grouplist = [];
    //无需要权限判断的方法
    protected $noNeedRight = ['roletree'];

    public function initialize()
    {
        parent::initialize();
        $this->model = model('AuthGroup');
        $this->childrenGroupIds = $this->auth->getChildrenGroupIds(true);
        $groupList = collection(AuthGroup::where('itemid', 'in', $this->childrenGroupIds)->select())->toArray();
        Tree::instance()->init($groupList, 'pid',' ');
        $result = [];
        if ($this->auth->isSuperAdmin()){
            $result = Tree::instance()->getTreeList(Tree::instance()->getTreeArray(0), 'name');
        }else{
            $groups = $this->auth->getGroups();
            foreach ($groups as $m => $n)
            {
                $result = array_merge($result, Tree::instance()->getTreeList(Tree::instance()->getTreeArray($n['pid'])));
            }
        }
        $groupName = [];
        foreach ($result as $k => $v)
        {
            $groupName[$v['itemid']] = $v['name'];
        }

        $this->grouplist = $result;
        $this->assignconfig("admin", ['id' => $this->auth->itemid, 'group_ids' => $this->auth->getGroupIds()]);
        //print_r($this->grouplist);exit;
        $this->view->assign('grouplist', $this->grouplist);
    }

    //查看
    public function index(){
		$columnlist = Cols::columnread('authgroup');
		$flag = array();$options = array();
		foreach($columnlist as $v){
			$flag[] = $v['listorder'];
            if($v['options']&&$v['isshowlist']==1){
                //把带有选项的列，提取出来。
                $options[$v['columnenname']] = $v['options'];
            }
 		}
		array_multisort($flag, SORT_ASC, $columnlist);
		//设置过滤方法
		$this->request->filter(['strip_tags']);
		//如果发送的来源是Selectpage，则转发到Selectpage
		if ($this->request->request('pkey_name')){
				return $this->selectpage();
		}
		$searchfileds = array();
        $searchdefault = array();
        $searchfileds['name'] = 'varcharshort';
        $searchfileds['pid'] = 'guid';
        $searchdefault['pid'] = '';
		list($where, $sort, $order, $offset, $limit) = $this->buildparams($searchfileds,null,$searchdefault);
        $limit = 200;
		$order = 'desc';
		$sort = 'itemid';
        //print_r($where);
		$total = $this->model->where($where)->order($sort, $order)->count();
		$totalpage = 1;$page = 1;
		if($limit>0){
				$totalpage = $total%$limit==0?intval($total/$limit):intval($total/$limit)+1;
				//总页数
				if($offset>0){$page = intval($offset/$limit)+1;}
		}
		$list = $this->model->where($where)->order($sort, $order)->limit($offset, $limit)->select();

		for ($i = 0; $i < count($list); $i++) {
            unset($list[$i]['intro']);unset($list[$i]['content']);
            foreach ($options as $k => $v) {
                if(isset($list[$i][$k])){
                    $arj = json_decode($v,true);
                    $sarj = $arj[$list[$i][$k]];
                    $list[$i][$k] = $sarj;
                }
            }
			
		}
        //print_r($list);exit;
        $result = array("total" => $total, "rows" => $list);
		$this->view->assign("lists",$result['rows']);
        $this->view->assign("listsjson",json_encode($result['rows']));
        $this->view->assign("columnlistjson",json_encode($columnlist));
        $this->view->assign("columnlist",$columnlist);
		$this->view->assign("total",$result['total']);
		$this->view->assign("offset",$offset);
		$this->view->assign("limit",$limit);
		$this->view->assign("totalpage",$totalpage);
		$this->view->assign("page",$page);
		return $this->view->fetch('index');
 	}

    //添加
    public function add()
    {
        if ($this->request->isPost())
        {
            $params = $this->request->post("row/a", [], 'strip_tags');
            $params['rules'] = explode(',', $params['rules']);
            if (!in_array($params['pid'], $this->childrenGroupIds)){
                $this->error(__('The parent group can not be its own child'));
            }
            $parentmodel = model("AuthGroup")->get($params['pid']);
            if (!$parentmodel){
                $this->error(__('The parent group can not found'));
            }
            // 父级别的规则节点
            $parentrules = explode(',', $parentmodel->rules);
            // 当前组别的规则节点
            $currentrules = $this->auth->getRuleIds();
            $rules = $params['rules'];
            // 如果父组不是超级管理员则需要过滤规则节点,不能超过父组别的权限
            $rules = in_array('*', $parentrules) ? $rules : array_intersect($parentrules, $rules);
            // 如果当前组别不是超级管理员则需要过滤规则节点,不能超当前组别的权限
            $rules = in_array('*', $currentrules) ? $rules : array_intersect($currentrules, $rules);
            $params['rules'] = implode(',', $rules);
            $params['itemid'] = str_replace('-','',Random::uuid());
            if(!$params['interfaces']){
                $params['interfaces'] = '*';
            }
            if ($params)
            {
                $this->model->create($params);
                $this->success();
            }
            $this->error();
        }
        return $this->view->fetch();
    }

    //编辑
    public function edit($ids = NULL)
    {
        $row = $this->model->get(['itemid' => $ids]);
        if (!$row)
            $this->error(__('No Results were found'));
        if ($this->request->isPost())
        {
            $params = $this->request->post("row/a", [], 'strip_tags');
            // 父节点不能是它自身的子节点
            if (!in_array($params['pid'], $this->childrenGroupIds))
            {
                $this->error(__('The parent group can not be its own child'));
            }
            $params['rules'] = explode(',', $params['rules']);

            $parentmodel = model("AuthGroup")->get($params['pid']);
            if (!$parentmodel)
            {
                $this->error(__('The parent group can not found'));
            }
            // 父级别的规则节点
            $parentrules = explode(',', $parentmodel->rules);
            // 当前组别的规则节点
            $currentrules = $this->auth->getRuleIds();
            $rules = $params['rules'];
            // 如果父组不是超级管理员则需要过滤规则节点,不能超过父组别的权限
            $rules = in_array('*', $parentrules) ? $rules : array_intersect($parentrules, $rules);
            // 如果当前组别不是超级管理员则需要过滤规则节点,不能超当前组别的权限
            $rules = in_array('*', $currentrules) ? $rules : array_intersect($currentrules, $rules);
            //print_r($params);exit;
            $params['rules'] = implode(',', $rules);
            if(!$params['interfaces']){
                $params['interfaces'] = '*';
            }
            if ($params)
            {
                $row->save($params);
                $this->success();
            }
            $this->error();
            return;
        }
        $this->view->assign("row", $row);
        return $this->view->fetch();
    }

    /**
     * 删除
     */
    public function del($ids = "")
    {
        //print_r($ids);exit;
        if ($ids)
        {
            $ids = explode(',', $ids);
            $grouplist = $this->auth->getGroups();
            $group_ids = array_map(function($group) {
                return $group['itemid'];
            }, $grouplist);
            // 移除掉当前管理员所在组别
            $ids = array_diff($ids, $group_ids);

            // 循环判断每一个组别是否可删除
            $grouplist = $this->model->where('itemid', 'in', $ids)->select();
            $groupaccessmodel = model('AuthGroupAccess');
            foreach ($grouplist as $k => $v)
            {
                // 当前组别下有管理员
                $groupone = $groupaccessmodel->get(['group_id' => $v['itemid']]);
                if ($groupone)
                {
                    //过滤有管理员的组别
                    $ids = array_diff($ids, [$v['itemid']]);
                    continue;
                }
                // 当前组别下有子组别
                $groupone = $this->model->get(['pid' => $v['itemid']]);
                if ($groupone)
                {
                    $ids = array_diff($ids, [$v['itemid']]);
                    continue;
                }
            }
            if (!$ids)
            {
                $this->error(__('You can not delete group that contain child group and administrators'));
            }
            $count = $this->model->where('itemid', 'in', $ids)->delete();
            if ($count)
            {
                $this->success();
            }
        }
        $this->error();
    }

    /**
     * 批量更新
     * @internal
     */
    public function multi($ids = "")
    {
        // 组别禁止批量操作
        $this->error();
    }

    /**
    * 读取角色权限树
    *
    * @internal
    */
    public function roletree(){
        $this->loadlang('auth/group');
        $model = model('AuthGroup');
        $id = $this->request->post("id");
        $pid = $this->request->post("pid");
        $parentGroupModel = $model->get($pid);
        $currentGroupModel = NULL;
        if ($id){
            $currentGroupModel = $model->get($id);
        }
        if (($pid || $parentGroupModel) && (!$id || $currentGroupModel)){
            $id = $id ? $id : NULL;
            $ruleList = collection(model('AuthRule')->order('weigh', 'desc')->select())->toArray();
            
            //读取父类角色所有节点列表
            $parentRuleList = [];
            
            if (in_array('*', explode(',', $parentGroupModel->rules)))
            {
                $parentRuleList = $ruleList;
            }
            else
            {
                $parentRuleIds = explode(',', $parentGroupModel->rules);
                foreach ($ruleList as $k => $v)
                {
                    if (in_array($v['itemid'], $parentRuleIds))
                    {
                        $parentRuleList[] = $v;
                    }
                }
            }
            //print_r(json_encode($parentRuleList));exit;
            
            //当前所有正常规则列表
            Tree::instance()->init($parentRuleList);
            //读取当前角色下规则ID集合
            $adminRuleIds = $this->auth->getRuleIds();
            //是否是超级管理员
            $superadmin = $this->auth->isSuperAdmin();
            //当前拥有的规则ID集合
            $currentRuleIds = $id ? explode(',', $currentGroupModel->rules) : [];

            if (!$id || !in_array($pid, Tree::instance()->getChildrenIds($id, TRUE))){
                $parentRuleList = Tree::instance()->getTreeList(Tree::instance()->getTreeArray(''), 'name');
                $hasChildrens = [];
                foreach ($parentRuleList as $k => $v){
                    if ($v['haschild'])
                        $hasChildrens[] = $v['itemid'];
                }
                $parentRuleIds = array_map(function($item) {
                    return $item['itemid'];
                }, $parentRuleList);
                $nodeList = [];
                foreach ($parentRuleList as $k => $v){
                    if (!$superadmin && !in_array($v['itemid'], $adminRuleIds))
                        continue;
                    if ($v['pid'] && !in_array($v['pid'], $parentRuleIds))
                        continue;
                    $state = array('selected' => in_array($v['itemid'], $currentRuleIds) && !in_array($v['itemid'], $hasChildrens));
                    $nodeList[] = array('id' => $v['itemid'], 'parent' => $v['pid'] ? $v['pid'] : '#', 'text' => __($v['title']), 'type' => 'menu', 'state' => $state);
                }
                $this->success('', null, $nodeList);
            }else{
                $this->error(__('Can not change the parent to child'));
            }
        }else{
            $this->error(__('Group not found'));
        }
    }
    /**
    * 读取角色的接口权限树
    *
    * @return 返回控制器函数的描述
    */
    public function roleinterface(){
        $this->loadlang('auth/group');
        $model = model('AuthGroup');
        $id = $this->request->post("id");
        $pid = $this->request->post("pid");
        $parentGroupModel = $model->get($pid);
        $currentGroupModel = NULL;
        if ($id){
            $currentGroupModel = $model->get($id);
        }
        if (($pid || $parentGroupModel) && (!$id || $currentGroupModel)){
            $id = $id ? $id : NULL;
            $ruleList = collection(model('AuthRule')->order('weigh', 'desc')->select())->toArray();
                        
            $moduleDir = ROOT_PATH . 'application' . DS .'admin' . DS . 'controller' . DS;
            if (!is_dir($moduleDir)) {
                throw new Exception('module not found');
            }
            if (version_compare(PHP_VERSION, '7.0.0', '<')) {
                if (extension_loaded('Zend OPcache')) {
                    $configuration = opcache_get_configuration();
                    $directives = $configuration['directives'];
                    $configName = request()->isCli() ? 'opcache.enable_cli' : 'opcache.enable';
                    if (!$directives[$configName]) {
                        throw new Exception("Please make sure {$configName} is turned on, Get help:https://forum.fastadmin.net/d/1321");
                    }
                } else {
                    throw new Exception("Please make sure opcache already enabled, Get help:https://forum.fastadmin.net/d/1321");
                }
            }
            
            $files = new \RecursiveIteratorIterator(
                new \RecursiveDirectoryIterator($moduleDir), \RecursiveIteratorIterator::LEAVES_ONLY
            );
            $delarray = config('noneedright.');
            
            foreach ($files as $name => $file) {
                if (!$file->isDir()) {
                    $filePath = $file->getRealPath();
                    $filename = $file->getFileName();//获取文件名
                    if(in_array($filename, $delarray['rightarr'])){
                        continue;
                    }
                    //echo strpos($filePath,'\\general\\');
                    if(strpos($filePath,'\\general\\')){
                        continue;
                    }
                    $contents = file_get_contents($filePath);
                    $namespace = $class = "";
                    $getting_namespace = false;$getting_class = false;
                    foreach (token_get_all($contents) as $token) {
                        //If this token is the namespace declaring, then flag that the next tokens will be the namespace name
                        if (is_array($token) && $token[0] == T_NAMESPACE) {
                            $getting_namespace = true;
                        }
                        //If this token is the class declaring, then flag that the next tokens will be the class name
                        if (is_array($token) && $token[0] == T_CLASS) {
                            $getting_class = true;
                        }
                        //While we're grabbing the namespace name...
                        if ($getting_namespace === true) {
                            //If the token is a string or the namespace separator...
                            if (is_array($token) && in_array($token[0], [T_STRING, T_NS_SEPARATOR])) {
                                //Append the token's value to the name of the namespace
                                $namespace .= $token[1];
                            } else if ($token === ';') {
                                //If the token is the semicolon, then we're done with the namespace declaration
                                $getting_namespace = false;
                            }
                        }
                        //While we're grabbing the class name...
                        if ($getting_class === true) {
                            //If the token is a string, it's the name of the class
                            if (is_array($token) && $token[0] == T_STRING) {
                                //Store the token's value as the class name
                                $class = $token[1];
                                //Got what we need, stope here
                                break;
                            }
                        }
                    }
                    $classes[] = $namespace ? $namespace . '\\' . $class : $class;
                }
            }
            $output = array();
            $c = 0;
            foreach ($classes as $class){
                //获取了控制器函数的注释
                $output = Extractor::getAllClassAnnotations($class);
            }
            $parentRuleList = array();

            foreach ($output as $k => $v) {
                $arr = explode('\\',$k);
                $ary = array();
                $ary['itemid'] = $arr[0];
                $ary['pid'] = '';
                $ary['name'] = $arr[0]; 
                $ary['title'] = $arr[0];
                $ary['icon'] = 'fa fa-circle-o';
                $ary['weight'] = 0;
                $parentRuleList[] = $ary;
                //添加第一个
                if(isset($arr[1])){
                    $ary['itemid'] = $arr[1];
                    $ary['pid'] = $arr[0];
                    $ary['name'] = $arr[1]; 
                    $ary['title'] = $arr[1];
                    $ary['icon'] = 'fa fa-circle-o';
                    $ary['weight'] = 1;
                    $parentRuleList[] = $ary;
                }
                foreach ($v as $kk => $vv) {
                    $ary = array();
                    $ary['pid'] = isset($arr[1])?$arr[1]:$arr[0];
                    $ary['icon'] = 'fa fa-circle-o';
                    $ary['weight'] = 2;
                    foreach ($vv as $kkk => $val) {
                        switch($kkk){
                            case 'ApiRoute':
                                $ary['itemid'] = $vv['ApiRoute'][0];
                                $ary['name'] = $vv['ApiRoute'][0];
                            break;
                            case 'ApiTitle':
                                $ary['title'] = $vv['ApiTitle'][0].'|'.$kk;
                            break;
                        }
                    }
                    $parentRuleList[] = $ary;
                }
            }
            
            //当前所有正常规则列表
            Tree::instance()->init($parentRuleList);
            //读取当前角色下规则ID集合
            $adminRuleIds = $this->auth->getInterfaceIds();
            //是否是超级管理员
            $superadmin = $this->auth->isSuperAdmin();
            //当前拥有的规则ID集合
            $currentRuleIds = $id ? explode(',', $currentGroupModel->interfaces) : [];

            if (!$id || !in_array($pid, Tree::instance()->getChildrenIds($id, TRUE))){
                $parentRuleList = Tree::instance()->getTreeList(Tree::instance()->getTreeArray(''), 'name');
                $hasChildrens = [];
                foreach ($parentRuleList as $k => $v){
                    if ($v['haschild'])
                        $hasChildrens[] = $v['itemid'];
                }
                $parentRuleIds = array_map(function($item) {
                    return $item['itemid'];
                }, $parentRuleList);
                $nodeList = [];
                foreach ($parentRuleList as $k => $v){
                    if (!$superadmin && !in_array($v['itemid'], $adminRuleIds))
                        continue;
                    if ($v['pid'] && !in_array($v['pid'], $parentRuleIds))
                        continue;
                    $state = array('selected' => in_array($v['itemid'], $currentRuleIds) && !in_array($v['itemid'], $hasChildrens));
                    $nodeList[] = array('id' => $v['itemid'], 'parent' => $v['pid'] ? $v['pid'] : '#', 'text' => __($v['title']), 'type' => 'menu', 'state' => $state);
                }
                $this->success('', null, $nodeList);
            }else{
                $this->error(__('Can not change the parent to child'));
            }
        }else{
            $this->error(__('Group not found'));
        }
    }
}
